package com.hanhai.zrb.api.mongodb.demo;

import java.net.UnknownHostException;
import java.util.Date;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.WriteResult;

/**
 * MongoDB-CRUD Demo。
 * 
 * 
 */
public class MongoDBDemo {
	// /////////////数据库地址常量/////////////////////
	/**
	 * 数据库地址
	 */
	public static final String DEFAULT_HOST = "localhost";// localhost
	/**
	 * 端口号
	 */
	public static final int DEFAULT_PORT = 27017;
	// //////////////数据库名称和集合常量/////////////////
	/**
	 * 数据库名称
	 */
	public static final String DB_BLOG = "blog";
	/**
	 * 集合名称
	 */
	public static final String DB_BLOG_COLLECTION = "article";

	// /////////////文章Article的属性名称常量/////////////////////
	/**
	 * 标题
	 */
	public static final String TITLE = "title";
	/**
	 * 内容
	 */
	public static final String CONTENT = "content";
	/**
	 * 作者
	 */
	public static final String AUTHOR = "author";
	/**
	 * 日期
	 */
	public static final String DATE = "date";
	public static final String ID = "id";

	public static void main(String[] args) throws UnknownHostException {

		Mongo mongo = new Mongo(DEFAULT_HOST, DEFAULT_PORT);
		// 获得数据库
		DB blogDb = mongo.getDB(DB_BLOG);
		DBCollection articleCollection = blogDb
				.getCollection(DB_BLOG_COLLECTION);

		buildThreeArticles(articleCollection);

		// 查找并打印作者为"FansUnion"的文章
		BasicDBObject searchArticleByAuthor = new BasicDBObject();
		searchArticleByAuthor.append(AUTHOR, "FansUnion");

		demoFindByField(articleCollection, searchArticleByAuthor);
		demoFindAndSort(articleCollection, searchArticleByAuthor);

		BasicDBObject searchArticleById = new BasicDBObject();
		searchArticleById.append(ID, 3L);
		demoFindById(articleCollection, searchArticleById);

		demoFindSpecialField(articleCollection, searchArticleById);

		demoFindWithIn(articleCollection);

		demoUpdateWithTwoWay(articleCollection, searchArticleByAuthor);

		demoRemove(articleCollection);
		// 集合中的文档数量
		long count = articleCollection.count();
		println("删除了刚刚新建的3条记录，剩余count=" + count);

		// 关闭连接
		mongo.close();
	}

	//删除数据
	private static void demoRemove(DBCollection articleCollection) {
		// 删除
		BasicDBObject removeCondition = new BasicDBObject();
		removeCondition.append(AUTHOR, "FansUnion");
		articleCollection.remove(removeCondition);

		BasicDBObject removeCondition2 = new BasicDBObject();
		removeCondition.append(TITLE, "HelloWorld");
		// 删除，并查看是否有报错
		WriteResult writeResult = articleCollection.remove(removeCondition2);
		CommandResult commandResult = writeResult.getLastError();
		println("查看error信息，发现err字段为空" + commandResult.toString());

		BasicDBObject removeAll = new BasicDBObject();
		articleCollection.remove(removeAll);
	}

	//2种方式更新对象
	private static void demoUpdateWithTwoWay(DBCollection articleCollection,
			BasicDBObject searchArticleByAuthor) {
		// 把标题为"HelloWorld"的文章的作者，修改为“小雷”
		println("把标题为HelloWorld的文章的作者，修改为小雷,只修改AUTHOR1个字段");
		// 查询条件：标题为"HelloWorld"
		BasicDBObject updateCondition = new BasicDBObject();
		searchArticleByAuthor.append(TITLE, "HelloWorld");

		BasicDBObject newHelloWorldArticle = new BasicDBObject();
		newHelloWorldArticle.append(AUTHOR, "小雷");

		// 第1种方式-修改，只修改指定的字段("$set","$inc"都是修改器)
		// update Article set author="小雷" where title='HelloWorld'
		DBObject updateSetValue = new BasicDBObject("$set",
				newHelloWorldArticle);
		articleCollection.update(updateCondition, updateSetValue);
		// 打印第1次修改过的"HelloWorld"文章
		DBObject helloWordlArticle2 = articleCollection
				.findOne(updateCondition);
		print(helloWordlArticle2);

		// 第2种方式-修改
		// update Article set author="小雷",title=null,content=null,date=null
		// where title='HelloWorld'
		println("把标题为HelloWorld的文章的作者，修改为小雷,修改了所有的字段");
		articleCollection.update(updateCondition, newHelloWorldArticle);
		DBObject helloWordlArticle = articleCollection.findOne(updateCondition);
		// 打印第2次修改过的"HelloWorld"文章
		print(helloWordlArticle);
	}

	//Mongodb中的in语句
	private static void demoFindWithIn(DBCollection articleCollection) {
		// IN查询
		println("查找并打印ID为1和2的文章");
		// List list = Arrays.asList(1,2);
		// Long[] array= new Long[]{1L,2L};

		BasicDBList values = new BasicDBList();
		values.add(1);
		values.add(2);

		DBObject inQuery = new BasicDBObject("$in", values);

		DBObject con = new BasicDBObject();
		con.put(ID, inQuery);
		DBCursor cursorIdArray = articleCollection.find(con);
		println("个数：" + cursorIdArray.count());
		while (cursorIdArray.hasNext()) {
			print(cursorIdArray.next());
		}
	}

	//查询特定的字段
	private static void demoFindSpecialField(DBCollection articleCollection,
			BasicDBObject searchArticleById) {
		println("查找并打印ID为3的文章2，只查询TITLE字段");
		BasicDBObject b = new BasicDBObject();
		b.append(TITLE, 1);
		DBCursor cursor3 = articleCollection.find(searchArticleById, b);
		println("个数：" + cursor3.count());
		while (cursor3.hasNext()) {
			print(cursor3.next());
		}
		// cursor3.close();//在没有这行代码的情况下，同样的程序，出现了1次，个数为4，仔细看，发现他们的内置ID不一样
		// 可能是上一次执行的删除，还没有完成？
		//这个地方是一个疑问，但是复现不了
	}

	//根据ID查找对象
	private static BasicDBObject demoFindById(DBCollection articleCollection,
			BasicDBObject searchArticleById) {
		// 查找并打印ID为3的文章
		println("查找并打印ID为3的文章");

		DBCursor cursor2 = articleCollection.find(searchArticleById);
		println("个数：" + cursor2.count());
		while (cursor2.hasNext()) {
			print(cursor2.next());
		}
		cursor2.close();
		return searchArticleById;
	}

	//查找对象,并排序
	private static void demoFindAndSort(DBCollection articleCollection,
			BasicDBObject searchArticleByAuthor) {
		// 查找并打印作者为"FansUnion"的文章,按照ID降序排列
		println("查找并打印作者为FansUnion的文章，降序排列，查询出来的ID一次为3,2,1");
		BasicDBObject orderByIdDesc = new BasicDBObject();
		orderByIdDesc.append(ID, -1);
		DBCursor cursorIdDesc = articleCollection.find(searchArticleByAuthor)
				.sort(orderByIdDesc);
		while (cursorIdDesc.hasNext()) {
			print(cursorIdDesc.next());
		}
	}

	//根据字段查找对象
	private static void demoFindByField(DBCollection articleCollection,
			BasicDBObject searchArticleByAuthor) {
		println("查找并打印作者为FansUnion的文章，查询出来的ID一次为1，2，3");
		DBCursor cursor = articleCollection.find(searchArticleByAuthor);
		while (cursor.hasNext()) {
			print(cursor.next());
		}
		cursor.close();// 网上和书中的的例子，没有关闭游标，官方JDK文档“kills the current cursor on
						// the server.”
	}

	// 构造3个文章,插入的ID顺序是1，2，3
	private static void buildThreeArticles(DBCollection articleCollection) {

		BasicDBObject article = buildArticle("做好社会主义的接班人", "好好学习，天天向上",
				"FansUnion", new Date(), 1L);
		BasicDBObject article2 = buildArticle("做好资本主义的掘墓人", "拼命干活，时时向上",
				"FansUnion", new Date(), 2L);
		BasicDBObject article3 = buildArticle("HelloWorld",
				"I am a MongoDb demo.", "FansUnion", new Date(), 3L);
		// 增加若干文章
		articleCollection.insert(article);
		articleCollection.insert(article2);
		articleCollection.insert(article3);

		println("插入文章的个数：" + articleCollection.count());
	}

	// 打印对象
	private static void print(DBObject article) {
		// println("-----------------------");
		println("内置ID：" + article.get("_id"));
		println("标题：" + article.get(TITLE));
		println("内容：" + article.get(CONTENT));
		println("作者：" + article.get(AUTHOR));
		println("日期：" + article.get(DATE));
		println("ID：" + article.get(ID));
		println("-----------------------");
	}

	private static void println(Object object) {
		System.out.println(object);
	}

	/**
	 * 构造1个文章对象
	 * 
	 * @param title
	 *            标题
	 * @param content
	 *            内容
	 * @param author
	 *            作者
	 * @param date
	 *            日期
	 * @return 文章对象
	 */
	private static BasicDBObject buildArticle(String title, String content,
			String author, Date date, Long id) {
		BasicDBObject article = new BasicDBObject();
		article.append(TITLE, title);
		article.append(CONTENT, content);
		article.append(AUTHOR, author);
		article.append(DATE, date);
		article.append(ID, id);
		return article;
	}
}